package cn.wlinker.video.monitor.controller;

import cn.hutool.core.date.DateUtil;
import cn.wlinker.video.monitor.brand.hikversion.HikVisionAccessPlatformEnum;
import cn.wlinker.video.monitor.brand.hikversion.create.net.HCNetTools;
import cn.wlinker.video.monitor.brand.hikversion.create.net.aop.HikCameraAspect;
import cn.wlinker.video.monitor.brand.hikversion.utils.NetDeviceCacheUtils;
import cn.wlinker.video.monitor.domain.dto.MonitorDeviceDTO;
import cn.wlinker.video.monitor.stream.ConverterFactories;
import cn.wlinker.video.monitor.utils.VideoKeyUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PipedInputStream;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

@Slf4j
@Api(tags = "海康网络设备-录像回放原始流转flv流输出")
@RestController
@RequestMapping("/api/hikNet")
public class NetPlayBackController {
    
    @Resource
    HikCameraAspect aspect;
 
    @GetMapping(value = "/playBackVideoOne")
    @ApiOperation(value = "海康网络设备-录像回放（基于原始流）-通道不复用",  notes = "响应通道不复用，但较稳定")
    @Async
    public void playBackVideo2(@RequestParam String id, @RequestParam String startTime, @RequestParam String endTime, HttpServletResponse httpServletResponse) throws InterruptedException, IOException {
        //设置响应头
        httpServletResponse.setContentType("video/x-flv");
        httpServletResponse.setHeader("Connection", "keep-alive");
        httpServletResponse.setStatus(HttpServletResponse.SC_OK);
        httpServletResponse.flushBuffer();
        MonitorDeviceDTO monitorDeviceDTO = VideoKeyUtils.getMonitorDeviceDtoById(id);
        String deviceCode = monitorDeviceDTO.getDeviceCode();
        String accessPlatform = monitorDeviceDTO.getAccessPlatform();
        if (!HikVisionAccessPlatformEnum.net.getAccessPlatform().equals(accessPlatform)) {
            throw new RuntimeException("不支持该平台");
        }
        LocalDateTime startLocalTime = DateUtil.parseLocalDateTime(startTime);
        LocalDateTime endLocalTime = DateUtil.parseLocalDateTime(endTime);
        //单次录像下载时长范围不能超过一小时
        if (startLocalTime.isAfter(endLocalTime)) {
            throw new RuntimeException("开始时间不能大于结束时间");
        }
        if (startLocalTime.plusHours(1).isBefore(endLocalTime)) {
            throw new RuntimeException("时间区间不能超过一小时");
        }
        Integer channelNo = monitorDeviceDTO.getChannelNo();
        aspect.logout(deviceCode);
        aspect.login(deviceCode);
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;
        HCNetTools hcNetTools = NetDeviceCacheUtils.getHcNetTools(deviceCode);
        try (PipedInputStream inputStream = new PipedInputStream(1024 * 1024);) {
            Thread thread = Thread.currentThread();
            // 启动下载线程：将数据写入管道输出流
            hcNetTools.playBackByTime(startLocalTime, endLocalTime, channelNo, thread, inputStream);
            // 最多等待5秒（配置响应超时时间）
            long delayNanos = TimeUnit.SECONDS.toNanos(5);
            LockSupport.parkNanos(delayNanos);
            // 配置日志级别
            avutil.av_log_set_level(avutil.AV_LOG_FATAL);
            // 配置FFmpegFrameGrabber从管道输入流读取
            grabber = new FFmpegFrameGrabber(inputStream);
            // 明确指定输入格式（部分流需要）
            grabber.setFormat("mpeg");
            grabber.setOption("stimeout", "500000");
            //设置缓存大小，提高画质、减少卡顿花屏
            grabber.setOption("buffer_size", "1024000");
            grabber.start();
            // 配置FFmpegFrameRecorder直接输出FLV到HTTP响应流
            //创建转码器
            recorder = new FFmpegFrameRecorder(
                    httpServletResponse.getOutputStream(), grabber.getImageWidth(),
                    grabber.getImageHeight(),
                    grabber.getAudioChannels());
            //配置转码器
            ConverterFactories.configRecorder(recorder, grabber);
            recorder.setVideoOption("color_range", "tv");
            recorder.start();
            Frame frame;
            while ((frame = grabber.grab()) != null) {
                recorder.record(frame);
            }
        } catch (Exception e) {
            log.error("播放视频时发生异常：{}", e.getMessage());
        } finally {
            // 释放资源
            if (recorder != null) {
                try {
                    recorder.close();
                } catch (Exception e) {
                    log.error("关闭recorder发生异常：{}", e.getMessage());
                }
            }
            if (grabber != null) {
                try {
                    grabber.close();
                } catch (Exception e) {
                    log.error("关闭grabber发生异常：{}", e.getMessage());
                }
            }
            hcNetTools.stopPlayback();
            hcNetTools.deviceLogout();
        }
    }
 
}